home *** CD-ROM | disk | FTP | other *** search
/ The Brain - Understandin…gh the Study of Addiction / The Brain Understanding Neurobiology Through the Study of Addiction.iso / mac / AcroReader4.0 / Plug-Ins / AcroForm / JavaScripts / AForm.js next >
Text File  |  1999-07-20  |  33KB  |  1,222 lines

  1. /*
  2.     ==========================================================================
  3.     Module: AForm.js
  4.     ==========================================================================
  5.     Pre-canned functions to map the user interface into JavaScripts.
  6.     ==========================================================================
  7.     The Software, including this file, is subject to the End User License
  8.     Agreement.
  9.     Copyright (c) 1998, Adobe Systems Incorporated, All Rights Reserved.
  10.     ==========================================================================
  11. */
  12.  
  13. console.println("Acrobat Forms Built-in Functions Version 4.0");
  14.  
  15. RE_NUMBER_ENTRY_DOT_SEP = new Array(
  16.     "[+-]?\\d*\\.?\\d*"
  17. );
  18. RE_NUMBER_COMMIT_DOT_SEP = new Array(
  19.     "[+-]?\\d+(\\.\\d+)?",        /* -1.0 or -1 */
  20.     "[+-]?\\.\\d+",                /* -.1 */
  21.     "[+-]?\\d+\\."                /* -1. */
  22. );
  23. RE_NUMBER_ENTRY_COMMA_SEP = new Array(
  24.     "[+-]?\\d*,?\\d*"
  25. );
  26. RE_NUMBER_COMMIT_COMMA_SEP = new Array(
  27.     "[+-]?\\d+([.,]\\d+)?",        /* -1,0 or -1 */
  28.     "[+-]?[.,]\\d+",                /* -,1 */
  29.     "[+-]?\\d+[.,]"                /* -1, */
  30. );
  31. RE_ZIP_ENTRY = new Array(
  32.     "\\d{0,5}"
  33. );
  34. RE_ZIP_COMMIT = new Array(
  35.     "\\d{5}"
  36. );
  37. RE_ZIP4_ENTRY = new Array(
  38.     "\\d{0,5}(\\.|[- ])?\\d{0,4}"
  39. );
  40. RE_ZIP4_COMMIT = new Array(
  41.     "\\d{5}(\\.|[- ])?\\d{4}"
  42. );
  43. RE_PHONE_ENTRY = new Array(
  44.     "\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",        /* 555-1234 or 408 555-1234 */
  45.     "\\(\\d{0,3}",                                            /* (408 */
  46.     "\\(\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",    /* (408) 555-1234 */
  47.         /* (allow the addition of parens as an afterthought) */
  48.     "\\(\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",    /* (408 555-1234 */
  49.     "\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}",    /* 408) 555-1234 */
  50.     "011(\\.|[- \\d])*"                                        /* international */
  51. );
  52. RE_PHONE_COMMIT = new Array(
  53.     "\\d{3}(\\.|[- ])?\\d{4}",                            /* 555-1234 */
  54.     "\\d{3}(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}",            /* 408 555-1234 */
  55.     "\\(\\d{3}\\)(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}",    /* (408) 555-1234 */
  56.     "011(\\.|[- \\d])*"                                    /* international */
  57. );
  58. RE_SSN_ENTRY = new Array(
  59.     "\\d{0,3}(\\.|[- ])?\\d{0,2}(\\.|[- ])?\\d{0,4}"
  60. );
  61. RE_SSN_COMMIT = new Array(
  62.     "\\d{3}(\\.|[- ])?\\d{2}(\\.|[- ])?\\d{4}"
  63. );
  64.  
  65. /* Function definitions for the color object. */
  66.  
  67. function ColorConvert(oColor, cColorspace)
  68. {    // Converts a color to a specific colorspace.
  69.     var oOut = oColor;
  70.  
  71.     switch (cColorspace) {
  72.         case "G":
  73.             // Note that conversion to the DeviceGray colorspace is lossy in the same
  74.             // way that a color signal on a B/W TV is lossy.
  75.             if (oColor[0] == "RGB")
  76.                 oOut = new Array("G", 0.3 * oColor[1] + 0.59 * oColor[2] + 0.11 * oColor[3]);
  77.             else if (oColor[0] == "CMYK")
  78.                 oOut = new Array("G", 1.0 - Math.min(1.0, 
  79.                     0.3 * oColor[1] + 0.59 * oColor[2] + 0.11 * oColor[3] + oColor[4]));
  80.         break;
  81.         case "RGB":
  82.             if (oColor[0] == "G")
  83.                 oOut = new Array("RGB", oColor[1], oColor[1], oColor[1]);
  84.             else if (oColor[0] == "CMYK")
  85.                 oOut = new Array("RGB", 1.0 - Math.min(1.0, oColor[1] + oColor[4]), 
  86.                     1.0 - Math.min(1.0, oColor[2] + oColor[4]),
  87.                     1.0 - Math.min(1.0, oColor[3] + oColor[4]));
  88.         break;
  89.         case "CMYK":
  90.             if (oColor[0] == "G")
  91.                 oOut = new Array("CMYK", 0, 0, 0, 1.0 - oColor[1]);
  92.             else if (oColor[0] == "RGB")
  93.                 oOut = new Array("CMYK", 1.0 - oColor[1], 1.0 - oColor[2], 1.0 - oColor[3], 0); 
  94.         break;
  95.     }
  96.  
  97.     return oOut;
  98. }
  99.  
  100. function ColorEqual(c1, c2)
  101. {    // Compare two colors. 
  102.     /* The gray colorspace conversion is lossy so we avoid if possible. */
  103.     if (c1[0] == "G")
  104.         c1 = color.convert(c1, c2[0]);
  105.     else
  106.         c2 = color.convert(c2, c1[0]);
  107.  
  108.     /* Colorspace must be equal. */
  109.     if (c1[0] != c2[0])    {
  110.         return false;
  111.     }
  112.  
  113.     /* Compare the individual components. */
  114.     var nComponents = 0;
  115.         
  116.     switch (c1[0]) {
  117.         case "G":
  118.             nComponents = 1;
  119.         break;
  120.         case "RGB":
  121.             nComponents = 3;
  122.         break;
  123.         case "CMYK":
  124.             nComponents = 4;
  125.         break;
  126.     }
  127.  
  128.     for (var i = 1; i <= nComponents; i++) {
  129.         if (c1[i] != c2[i])    {
  130.             return false;
  131.         }
  132.     }
  133.  
  134.     return true;
  135. }
  136.  
  137. /* ==== Convenience Objects ==== */
  138.  
  139. /* Stock color definitions for ease of use. */
  140. color = new Object();
  141. color.equal = ColorEqual;
  142. color.convert = ColorConvert;
  143. color.transparent = new Array("T");
  144. color.black = new Array("G", 0);
  145. color.white = new Array("G", 1);
  146. color.dkGray = new Array("G", 0.25);
  147. color.gray = new Array("G", 0.5);
  148. color.ltGray = new Array("G", 0.75);
  149. color.red = new Array("RGB", 1, 0, 0);
  150. color.green = new Array("RGB", 0, 1, 0);
  151. color.blue = new Array("RGB", 0, 0, 1);
  152. color.cyan = new Array("CMYK", 1, 0, 0, 0);
  153. color.magenta = new Array("CMYK", 0, 1, 0, 0);
  154. color.yellow = new Array("CMYK", 0, 0, 1, 0);
  155.  
  156. /* Font definitions for ease of use */
  157. font = new Object();
  158. font.Times = "Times-Roman";
  159. font.TimesB = "Times-Bold";
  160. font.TimesI = "Times-Italic";
  161. font.TimesBI = "Times-BoldItalic";
  162. font.Helv = "Helvetica";
  163. font.HelvB = "Helvetica-Bold";
  164. font.HelvI = "Helvetica-Oblique";
  165. font.HelvBI = "Helvetica-BoldOblique";
  166. font.Cour = "Courier";
  167. font.CourB = "Courier-Bold";
  168. font.CourI = "Courier-Oblique";
  169. font.CourBI = "Courier-BoldOblique";
  170. font.Symbol = "Symbol";
  171. font.ZapfD = "ZapfDingbats";
  172. font.KaGo = "HeiseiKakuGo-W5-UniJIS-UCS2-H";
  173. font.KaMi = "HeiseiMin-W3-UniJIS-UCS2-H";
  174.  
  175. /* Border style definitions for ease of use */
  176. border = new Object();
  177. border.s = "solid";
  178. border.d = "dashed";
  179. border.b = "beveled";
  180. border.i = "inset";
  181. border.u = "underline";
  182.  
  183. /* Radio/Check button style definitions for ease of use */
  184. style = new Object();
  185. style.ch = "check";
  186. style.cr = "cross";
  187. style.di = "diamond";
  188. style.ci = "circle";
  189. style.st = "star";
  190. style.sq = "square"; 
  191.  
  192. /* highlight modes of on a push button */
  193. highlight = new Object();
  194. highlight.n = "none";
  195. highlight.i = "invert";
  196. highlight.p = "push";
  197. highlight.o = "outline";
  198.  
  199. /* zoom types for a document */
  200. zoomtype = new Object();
  201. zoomtype.none = "NoVary";
  202. zoomtype.fitW = "FitWidth";
  203. zoomtype.fitH = "FitHeight";
  204. zoomtype.fitP = "FitPage";
  205. zoomtype.fitV = "FitVisibleWidth";
  206. zoomtype.pref = "Preferred";
  207.  
  208. /* Cursor behavior in full screen mode. */
  209. cursor = new Object();
  210. cursor.visible = 0;
  211. cursor.hidden = 1;
  212. cursor.delay = 2;
  213.  
  214. /* Transition definitions. */
  215. trans = new Object();
  216. trans.blindsH        = "Blinds Horizontal";
  217. trans.blindsV        = "Blinds Vertical";
  218. trans.boxI            = "Box In";
  219. trans.boxO            = "Box Out";
  220. trans.dissolve        = "Dissolve";
  221. trans.glitterD        = "Glitter Down";
  222. trans.glitterR        = "Glitter Right";
  223. trans.glitterRD        = "Glitter Right-Down";
  224. trans.none            = "No Transition";
  225. trans.random        = "Random Transition";
  226. trans.replace        = "Replace";
  227. trans.splitHI        = "Split Horizontal In";
  228. trans.splitHO        = "Split Horizontal Out";
  229. trans.splitVI        = "Split Vertical In";
  230. trans.splitVO        = "Split Vertical Out";
  231. trans.wipeD            = "Wipe Down";
  232. trans.wipeL            = "Wipe Left";
  233. trans.wipeR            = "Wipe Right";
  234. trans.wipeU            = "Wipe Up";
  235.  
  236. /* Icon/Text placement. */
  237. position = new Object();
  238. position.textOnly    = 0;
  239. position.iconOnly    = 1;
  240. position.iconTextV    = 2;
  241. position.textIconV    = 3;
  242. position.iconTextH    = 4;
  243. position.textIconH    = 5;
  244. position.overlay    = 6;
  245.  
  246. /* When does icon scale. */
  247. scaleWhen = new Object();
  248. scaleWhen.always    = 0;
  249. scaleWhen.never        = 1;
  250. scaleWhen.tooBig    = 2;
  251. scaleWhen.tooSmall    = 3;
  252.  
  253. /* How does icon scale. */
  254. scaleHow = new Object();
  255. scaleHow.proportional    = 0;
  256. scaleHow.anamorphic        = 1;
  257.  
  258.  
  259. /* Field display. */
  260. display = new Object();
  261. display.visible        = 0;
  262. display.hidden        = 1;
  263. display.noPrint        = 2;
  264. display.noView        = 3;
  265.  
  266. /* ==== Functions ==== */
  267.  
  268. /* these may be used a lot -- they are language independent */
  269.  
  270. AFDigitsRegExp = new RegExp();
  271. AFDigitsRegExp.compile("\\d+");
  272. AFPMRegExp = new RegExp();
  273. AFPMRegExp.compile(IDS_PM, "i");
  274. AFAMRegExp = new RegExp();
  275. AFAMRegExp.compile(IDS_AM, "i");
  276. AFTimeLongRegExp = new RegExp();
  277. AFTimeLongRegExp.compile("\\d{1,2}:\\d{1,2}:\\d{1,2}");
  278. AFTimeShortRegExp = new RegExp();
  279. AFTimeShortRegExp.compile("\\d{1,2}:\\d{1,2}");
  280.  
  281. function AFBuildRegExps(array)
  282. /* Takes an array of strings and turns it into an array of compiled regular
  283.  * expressions -- is used for the definitions that follow */
  284. {
  285.     var retVal = new Array();
  286.  
  287.     retVal.length = array.length;
  288.     for(var it = 0; it < array.length; it++)
  289.     {
  290.         retVal[it] = new RegExp();
  291.         retVal[it].compile(array[it], "i");
  292.     }
  293.     return retVal;
  294. }
  295.  
  296. /* these may be used a lot -- they are NOT language independent and are 
  297.  * derived from the localizable (RE_xxx) stuff above */
  298.  
  299. AFNumberDotSepEntryRegExp = AFBuildRegExps(RE_NUMBER_ENTRY_DOT_SEP);
  300. AFNumberDotSepCommitRegExp = AFBuildRegExps(RE_NUMBER_COMMIT_DOT_SEP);
  301. AFNumberCommaSepEntryRegExp = AFBuildRegExps(RE_NUMBER_ENTRY_COMMA_SEP);
  302. AFNumberCommaSepCommitRegExp = AFBuildRegExps(RE_NUMBER_COMMIT_COMMA_SEP);
  303. AFZipEntryRegExp = AFBuildRegExps(RE_ZIP_ENTRY);
  304. AFZipCommitRegExp = AFBuildRegExps(RE_ZIP_COMMIT);
  305. AFZip4EntryRegExp = AFBuildRegExps(RE_ZIP4_ENTRY);
  306. AFZip4CommitRegExp = AFBuildRegExps(RE_ZIP4_COMMIT);
  307. AFPhoneEntryRegExp = AFBuildRegExps(RE_PHONE_ENTRY);
  308. AFPhoneCommitRegExp = AFBuildRegExps(RE_PHONE_COMMIT);
  309. AFSSNEntryRegExp = AFBuildRegExps(RE_SSN_ENTRY);
  310. AFSSNCommitRegExp = AFBuildRegExps(RE_SSN_COMMIT);
  311. AFMonthsRegExp = AFBuildRegExps(IDS_MONTH_INFO.split(/\[\d+\]/));
  312.  
  313. function AFExactMatch(rePatterns, sString)
  314. {    /* match a string against an array of RegExps */
  315.     var it;
  316.  
  317.     if(!rePatterns.length && rePatterns.test(sString) && RegExp.lastMatch == sString)
  318.         return true;
  319.     for(it = 0; it < rePatterns.length; it++)
  320.         if(rePatterns[it].test(sString) && RegExp.lastMatch == sString)
  321.             return it + 1;
  322.     return 0;
  323. }
  324.  
  325. function AFExtractNums(string)
  326. {    /* returns an array of numbers that it managed to extract from the given 
  327.      * string or null on failure */
  328.     var nums = new Array();
  329.  
  330.     if (string.charAt(0) == '.' || string.charAt(0) == ',')
  331.         string = "0" + string;
  332.          
  333.     while(AFDigitsRegExp.test(string)) {
  334.         nums.length++;
  335.         nums[nums.length - 1] = RegExp.lastMatch;
  336.         string = RegExp.rightContext;
  337.     }
  338.     if(nums.length >= 1) return nums;
  339.     return null;
  340. }
  341.  
  342. function AFMakeNumber(string)
  343. {    /* attempts to make a number out of a string that may not use '.' as the
  344.      * seperator; it expects that the number is fairly well-behaved other than
  345.      * possibly having a non-JavaScript friendly separator */
  346.     var type = typeof string;
  347.  
  348.     if (type == "number")
  349.         return string;
  350.     if (type != "string")
  351.         return null;
  352.  
  353.     var array = AFExtractNums(string);
  354.  
  355.     if(array)
  356.     {
  357.         var joined = array.join(".");
  358.  
  359.         if (string.indexOf("-.") >= 0)
  360.             joined = "0." + joined;
  361.         return joined * (string.indexOf("-") >= 0 ? -1.0 : 1.0);
  362.     }
  363.     else
  364.         return null;
  365. }
  366.  
  367. function AFExtractRegExp(rePattern, string)
  368. {    /* attempts to match the pattern given against the string given; on 
  369.      * success, returns an array containing (at index 0) the initial
  370.      * string with the matched text removed and (at index 1) the matched
  371.      * text; on failure, returns null */
  372.     var retVal = new Array();
  373.  
  374.     if(rePattern.test(string))
  375.     {
  376.         retVal.length = 2;
  377.         retVal[0] = RegExp.leftContext + RegExp.rightContext;
  378.         retVal[1] = RegExp.lastMatch;
  379.         return retVal;
  380.     }
  381.     return null;
  382. }
  383.  
  384. function AFMakeArrayFromList(string)
  385. {
  386.   var type = typeof string;
  387.  
  388.   if(type == "string")
  389.   {
  390.      var reSep = new RegExp();
  391.     reSep.compile(",[ ]?");
  392.     return string.split(reSep);
  393.   }
  394.   return string;
  395. }
  396.  
  397. function AFExtractTime(string)
  398. {    /* attempts to extract a WELL FORMED time from a string; returned 
  399.      * is an array in the same vein as AFExtractRegExp or null on
  400.      * failure. a WELL FORMED time looks like 12:23:56pm */
  401.     
  402.     var pm = "";
  403.     var info;
  404.  
  405.     info = AFExtractRegExp(AFPMRegExp, string);
  406.     if(info)
  407.     {
  408.         pm = info[1];
  409.         string = info[0];
  410.     }
  411.     info = AFExtractRegExp(AFAMRegExp, string);
  412.     if(info)
  413.     {
  414.         string = info[0];
  415.     }
  416.     info = AFExtractRegExp(AFTimeLongRegExp, string);
  417.     if(info)
  418.     {
  419.         info[1] += pm;
  420.         return info;
  421.     }
  422.     info = AFExtractRegExp(AFTimeShortRegExp, string);
  423.     if(info)
  424.     {
  425.         info[1] += pm;
  426.         return info;
  427.     }
  428.  
  429.     return null;
  430. }
  431.  
  432. function AFGetMonthIndex(string)
  433. {    /* attempts to identify the given string as a month or a valid abbreviation,
  434.      * it expects the given string to be the valid month from the matced RegExp.
  435.      * returns the month index (January = 1) or zero on failure */
  436.     var monthre = new RegExp(string + "\\[(\\d+)\\]", "i");
  437.     var result = monthre.exec(IDS_MONTH_INFO);
  438.     
  439.     if(string && result) return 1.0 * result[1];
  440.     return 0;
  441. }
  442.  
  443. function AFMatchMonth(string)
  444. {    /* attempts to find a valid month embedded in a string; returns the month
  445.      * index (January = 1) or zero on failure */
  446.  
  447.     for(var it = 0; it < AFMonthsRegExp.length; it++)
  448.         if(AFMonthsRegExp[it].test(string))
  449.             return AFGetMonthIndex(RegExp.lastMatch);
  450.     return 0;
  451. }
  452.  
  453. function AFGetMonthString(index)
  454. {    /* returns the string corresponding to the given month or a string that
  455.      * is indicative of the fact that the index was invalid */
  456.     var monthre = new RegExp("(\\w+)\\[" + index + "\\]");
  457.     var result = monthre.exec(IDS_MONTH_INFO);
  458.  
  459.     if(result) return result[1];
  460.     return IDS_INVALID_MONTH;
  461. }
  462.  
  463. function AFParseTime(string, date)
  464. {    /* attempts to parse a string containing a time; returns null on failure
  465.      * or a Date object on success. Time can be in ugly format. */
  466.     var pm, am;
  467.     var nums = AFExtractNums(string);
  468.     if (!date)
  469.         date = new Date();
  470.     var hour, minutes, seconds;
  471.  
  472.     if(!string) return date;
  473.     if(!nums) return null;
  474.     if(nums.length < 2 || nums.length > 3) return null;
  475.     if(AFPMRegExp.test(string)) pm = true;
  476.     else pm = false;
  477.     if(AFAMRegExp.test(string)) am = true;
  478.     else am = false;
  479.     hour = new Number(nums[0]); /* force it to number */
  480.     if(pm)
  481.     {
  482.         if(hour < 12) hour += 12;
  483.     }
  484.     else if (am)
  485.     {
  486.         if(hour >= 12) hour -= 12;
  487.     }
  488.     minutes = nums[1];
  489.     if(nums.length == 3) seconds = nums[2];
  490.     else seconds = 0;
  491.     date.setHours(hour);
  492.     date.setMinutes(minutes);
  493.     date.setSeconds(seconds);
  494.     if(date.getHours() != hour)
  495.         return null;
  496.     if(date.getMinutes() != minutes)
  497.         return null;
  498.     if(date.getSeconds() != seconds)
  499.         return null;
  500.     return date;
  501. }
  502.  
  503. function AFDateFromYMD(nYear, nMonth, nDate)
  504. {    /* Validates the given fields and returns a date based on them */
  505.     var dDate = new Date();
  506.  
  507.     dDate.setFullYear(nYear, nMonth, nDate);
  508.     if(dDate.getFullYear() != nYear)
  509.         return null;
  510.     if(dDate.getMonth() != nMonth)
  511.         return null;
  512.     if(dDate.getDate() != nDate)
  513.         return null;
  514.     return dDate;
  515. }
  516.  
  517. function AFParseDateEx(cString, cOrder)
  518. {    /* Attempts to parse a string containing some form of date; returns null
  519.     ** on failure or a Date object on success. cOrder should be the order in
  520.     ** which the date is entered (e.g. ymd, mdy, etc.). Use AFParseDateOrder to
  521.     ** generate this string from an arbitrary format string. */
  522.     var nYear;
  523.     var nMonth;
  524.     var nDate;
  525.     var nYCount;
  526.     var dDate = new Date();
  527.  
  528.     dDate.setHours(12, 0, 0);
  529.  
  530.     /* Empty string returns current date/time. */
  531.     if (!cString) { 
  532.         return dDate;
  533.     }
  534.  
  535.     nYCount = AFParseDateYCount(cOrder); /* count the number of digits for year in the selected format */
  536.     cOrder = AFParseDateOrder(cOrder); /* make sure its in the "ymd" format */
  537.  
  538.     /* Extract any time information in the string. */
  539.     var info = AFExtractTime(cString);
  540.     if (info)
  541.         cString = info[0];
  542.  
  543.     /* Break down the date into an array of numbers. */
  544.     var aNums = AFExtractNums(cString);
  545.     if(!aNums) 
  546.         return null;    /* No numbers? */
  547.  
  548.     /* User supplied three numbers. */
  549.     if (aNums.length == 3) {
  550.         nYear = 1.0 * aNums[cOrder.indexOf("y")];
  551.         if (nYCount > 2 && nYear < 100)
  552.             return null; /* must enter 4 digits for the year to match with the format of the field */
  553.         nYear = AFDateHorizon(nYear);
  554.  
  555.         dDate = AFDateFromYMD(nYear, aNums[cOrder.indexOf("m")] - 1, aNums[cOrder.indexOf("d")]);
  556.         if (info)
  557.             dDate = AFParseTime(info[1], dDate);
  558.         return dDate;
  559.     }
  560.  
  561.     /* Find text based month, if supplied. */
  562.     nMonth = AFMatchMonth(cString);    
  563.  
  564.     /* User supplied two numbers. */
  565.     if(aNums.length == 2) {
  566.         if (nMonth) {
  567.             /* Easy case, the month was text and we have two numbers. */
  568.             if (cOrder.indexOf("y") < cOrder.indexOf("d")) {
  569.                 nYear = 1.0 * aNums[0];
  570.                 nDate = aNums[1];
  571.             } else {
  572.                 nYear = 1.0 * aNums[1];
  573.                 nDate = aNums[0];
  574.             }
  575.             if (nYCount > 2 && nYear < 100)
  576.                 return null; /* must enter 4 digits for the year to match with the format of the field */
  577.         
  578.             nYear = AFDateHorizon(nYear);
  579.             dDate = AFDateFromYMD(nYear, nMonth - 1, nDate);
  580.  
  581.             if (info)
  582.                 dDate = AFParseTime(info[1], dDate);
  583.             return dDate;
  584.         }
  585.  
  586.         /* More difficult case. We have two numbers and three slots, how
  587.         ** to allocate them? */
  588.         if (cOrder.indexOf("y") < cOrder.indexOf("d"))    {
  589.             /* Year comes before date and as such we allocate the two
  590.             ** numbers to the month and the year only. */
  591.             if (cOrder.indexOf("y") < cOrder.indexOf("m")) {
  592.                 nYear = 1.0 * aNums[0];
  593.                 nMonth = aNums[1];
  594.             } else {
  595.                 nYear = 1.0 * aNums[1];
  596.                 nMonth = aNums[0];
  597.             }
  598.             if (nYCount > 2 && nYear < 100)
  599.                 return null; /* must enter 4 digits for the year to match with the format of the field */
  600.         
  601.             nYear = AFDateHorizon(nYear);
  602.             dDate = AFDateFromYMD(nYear, nMonth - 1, 1);
  603.         } else {
  604.             /* Date comes before year and so we allocate the two numbers
  605.             ** to the date and the month only. */
  606.             nYear = dDate.getFullYear();
  607.             if (cOrder.indexOf("d") < cOrder.indexOf("m")) {
  608.                 dDate = AFDateFromYMD(nYear, aNums[1] - 1, aNums[0]);
  609.             } else {
  610.                 dDate = AFDateFromYMD(nYear, aNums[0] - 1, aNums[1]);
  611.             }
  612.         }
  613.     
  614.         if (info)
  615.             dDate = AFParseTime(info[1], dDate);
  616.         return dDate;
  617.     }
  618.  
  619.     /* User supplied one number. */
  620.     if(aNums.length == 1)    {
  621.         if (nMonth) {
  622.             /* We have one number and two slots (y/d) and need to allocate
  623.             ** them based on who came first in the format. */
  624.             if(cOrder.indexOf("y") < cOrder.indexOf("d")) {
  625.                 nYear = 1.0 * aNums[0];
  626.                 if (nYCount > 2 && nYear < 100)
  627.                     return null; /* must enter 4 digits for the year to match with the format of the field */
  628.             
  629.                 nYear = AFDateHorizon(nYear);
  630.                 dDate = AFDateFromYMD(nYear, nMonth - 1, 1);
  631.             } else {
  632.                 nYear = dDate.getFullYear();
  633.                 dDate = AFDateFromYMD(nYear, nMonth - 1, aNums[0]);
  634.             }
  635.             if (info)
  636.                 dDate = AFParseTime(info[1], date);
  637.             return dDate;
  638.         }
  639.  
  640.         /* We have one number and three slots and need to allocate them
  641.         ** based on who came first in the format. */
  642.         nYear = dDate.getFullYear();
  643.         nMonth = dDate.getMonth();
  644.         nDate = dDate.getDate();
  645.         switch (cOrder.charAt(0)) {
  646.             case "y":
  647.                 nYear = 1.0 * aNums[0];
  648.                 if (nYCount > 2 && nYear < 100)
  649.                     return null; /* must enter 4 digits for the year to match with the format of the field */
  650.             
  651.                 nYear = AFDateHorizon(nYear);
  652.             break;
  653.             case "m":
  654.                 nMonth = aNums[0] - 1;
  655.             break;
  656.             case "d":
  657.                 nDate = aNums[0];
  658.             break;
  659.         }
  660.         dDate = AFDateFromYMD(nYear, nMonth, nDate);
  661.  
  662.  
  663.         if (info)
  664.             dDate = AFParseTime(info[1], date);
  665.         return dDate;
  666.     }
  667.  
  668.     /* No idea how to deal with the other combinations. */
  669.     return null;
  670. }
  671.  
  672. function AFDateHorizon(nYear)
  673. {    /* Takes the year supplied and applies the date horizon heuristic.
  674.     ** All years between 50 and 100 we add 1900. All years less than 50 we add 2000. */
  675.     if (nYear < 100 && nYear >= 50) {
  676.         nYear += 1900;
  677.     } else if (nYear >= 0 && nYear < 50) {
  678.         nYear += 2000;
  679.     }
  680.  
  681.     return nYear;
  682. }
  683.  
  684. function AFParseDate(string, longEntry, shortEntry, wordMonthEntry, monthYearEntry)
  685. {    /* OBSOLETE: Use AFParseDateEx instead. */
  686.     var nums;
  687.     var year, month;
  688.     var date;
  689.     var info = AFExtractTime(string);
  690.  
  691.     if(!string) return new Date();
  692.  
  693.     if(info)
  694.         string = info[0];
  695.  
  696.     date = new Date();
  697.     nums = AFExtractNums(string);
  698.     if(!nums) return null;
  699.     if(nums.length == 3)
  700.     {
  701.         year = 1.0 * nums[eval(longEntry.charAt(0))];
  702.         year = AFDateHorizon(year);
  703.         date = AFDateFromYMD(year, nums[eval(longEntry.charAt(1))] - 1, nums[eval(longEntry.charAt(2))]);
  704.         if (info)
  705.             date = AFParseTime(info[1], date);
  706.         return date;
  707.     }
  708.     month = AFMatchMonth(string);
  709.     if(nums.length == 2)
  710.     {
  711.         if(month)
  712.         {
  713.             year = 1.0 * nums[eval(wordMonthEntry.charAt(0))];
  714.             year = AFDateHorizon(year);
  715.             date = AFDateFromYMD(year, month - 1, nums[eval(wordMonthEntry.charAt(1))]);
  716.             if (info)
  717.                 date = AFParseTime(info[1], date);
  718.             return date;
  719.         }
  720.         if(monthYearEntry)
  721.         {
  722.             year = 1.0 * nums[eval(monthYearEntry.charAt(0))];
  723.             year = AFDateHorizon(year);
  724.             date = AFDateFromYMD(year, nums[eval(monthYearEntry.charAt(1))] - 1, 1);
  725.         }
  726.         else
  727.             date = AFDateFromYMD(date.getFullYear(),
  728.                 nums[eval(shortEntry.charAt(0))] - 1,
  729.                 nums[eval(shortEntry.charAt(1))]);
  730.         if (info)
  731.             date = AFParseTime(info[1], date);
  732.         return date;
  733.     }
  734.     if(month && nums.length == 1)
  735.     {
  736.         if(monthYearEntry)
  737.         {
  738.             year = 1.0 * nums[0];
  739.             year = AFDateHorizon(year);
  740.             date = AFDateFromYMD(year, month - 1, 1);
  741.         }
  742.         else
  743.             date = AFDateFromYMD(date.getFullYear(), month - 1,    nums[0]);
  744.         if (info)
  745.             date = AFParseTime(info[1], date);
  746.         return date;
  747.     }
  748.  
  749.     return null;
  750. }
  751.  
  752. function AFParseDateWithPDF(value, pdf)
  753. { /* OBSOLETE: Use AFParseDateEx instead. */
  754.     var cOldFormats = new Array(
  755.         "m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy",
  756.         "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy",
  757.         "m/d/yy h:MM tt", "m/d/yy HH:MM" );
  758.    
  759.     return AFParseDateEx(value, cOldFormats[pdf]);
  760. }
  761.  
  762. function AFMergeChange(event)
  763. {    /* merges the last change with the uncommitted change */
  764.     var prefix, postfix;
  765.     var value = event.value;
  766.  
  767.     if(event.willCommit) return event.value;
  768.     if(event.selStart >= 0)
  769.         prefix = value.substring(0, event.selStart);
  770.     else prefix = "";
  771.     if(event.selEnd >= 0 && event.selEnd <= value.length)
  772.         postfix = value.substring(event.selEnd, value.length);
  773.     else postfix = "";
  774.     return prefix + event.change + postfix;
  775. }
  776.  
  777. function AFRange_Validate(bGreaterThan, nGreaterThan, bLessThan, nLessThan)
  778. {       /* This function validates the current event to ensure that its value is 
  779.     ** within the specified range. */
  780.     var cError = "";
  781.  
  782.     if (event.value == "")
  783.         return;
  784.  
  785.     if (bGreaterThan && bLessThan) {
  786.         if (event.value < nGreaterThan || event.value > nLessThan)
  787.             cError = util.printf(IDS_GT_AND_LT, nGreaterThan, nLessThan);
  788.     } else if (bGreaterThan) {
  789.         if (event.value < nGreaterThan)
  790.             cError = util.printf(IDS_GREATER_THAN, nGreaterThan);
  791.     } else if (bLessThan) {
  792.         if (event.value > nLessThan)
  793.             cError = util.printf(IDS_LESS_THAN, nLessThan);
  794.     }
  795.     
  796.     if (cError != "") {
  797.         app.alert(cError, 0);
  798.         event.rc = false;
  799.     }
  800. }
  801.  
  802. function AFSimpleInit(cFunction)
  803. {    /* Convenience function used by AFSimple_Calculate. */
  804.     switch (cFunction)
  805.     {
  806.         case "PRD":
  807.             return 1.0;
  808.             break;
  809.     }
  810.  
  811.     return 0.0;
  812. }
  813.  
  814. function AFSimple(cFunction, nValue1, nValue2)
  815. {    /* Convenience function used by AFSimple_Calculate. */
  816.     var nValue = 1.0 * nValue1;
  817.  
  818.     /* Have to do this otherwise JavaScript thinks it's dealing with strings. */
  819.     nValue1 = 1.0 * nValue1;
  820.     nValue2 = 1.0 * nValue2;
  821.  
  822.     switch (cFunction)
  823.     {
  824.         case "AVG":
  825.         case "SUM":
  826.             nValue = nValue1 + nValue2;
  827.             break;
  828.         case "PRD":
  829.             nValue = nValue1 * nValue2;
  830.             break;
  831.         case "MIN":
  832.             nValue = Math.min(nValue1,nValue2);
  833.             break;
  834.         case "MAX":
  835.             nValue = Math.max(nValue1, nValue2);
  836.             break;
  837.     }
  838.  
  839.     return nValue;
  840. }
  841.  
  842. function AFSimple_Calculate(cFunction, cFields)
  843. {   /* Calculates the sum, average, product, etc. of the listed field values. */
  844.     var nFields = 0;
  845.     var nValue = AFSimpleInit(cFunction);
  846.  
  847.     /* Field name separator is one or more spaces followed by a comma, 
  848.     ** followed by one or more spaces.
  849.     ** or an array of field names */
  850.      var aFields = AFMakeArrayFromList(cFields);
  851.  
  852.     for (var i = 0; i < aFields.length; i++) {
  853.         /* Found a field, process it's value. */
  854.         var f = this.getField(aFields[i]);
  855.         var a = f.getArray();
  856.  
  857.         for (var j = 0; j < a.length; j++) {
  858.             var nTemp = AFMakeNumber(a[j].value); 
  859.             if (i == 0 && j == 0 && (cFunction == "MIN" || cFunction == "MAX"))
  860.                 nValue = nTemp;
  861.             nValue = AFSimple(cFunction, nValue, nTemp);
  862.             nFields++;
  863.         }
  864.     }
  865.  
  866.     if (cFunction == "AVG" && nFields > 0)
  867.         nValue /= nFields;
  868.  
  869.     event.value = nValue;
  870. }
  871.  
  872. function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency, bCurrencyPrepend)
  873. {       /* This function validates the current keystroke event to make sure the
  874.         key pressed is reasonable for a numeric field. */
  875.  
  876.     var value = AFMergeChange(event);
  877.     var commit, noCommit;
  878.  
  879.     if(!value) return;
  880.     if(sepStyle > 1)
  881.     {
  882.         commit = AFNumberCommaSepCommitRegExp;
  883.         noCommit = AFNumberCommaSepEntryRegExp;
  884.     }
  885.     else
  886.     {
  887.         commit = AFNumberDotSepCommitRegExp;
  888.         noCommit = AFNumberDotSepEntryRegExp;
  889.     }
  890.     if(!AFExactMatch(event.willCommit ? commit : noCommit, value))
  891.     {
  892.         if (event.willCommit)
  893.             app.alert(IDS_INVALID_VALUE + " [ " + event.target.name + " ]", 0);
  894.         else
  895.             app.beep(0);
  896.         event.rc = false;
  897.     }
  898. }
  899.  
  900. function AFPercent_Keystroke(nDec, sepStyle)
  901. {
  902.         AFNumber_Keystroke(nDec, sepStyle, 0, 0, "", true);
  903. }
  904.  
  905. function AFSpecial_Keystroke(psf)
  906. {       /* This function validates the current keystroke event to make sure the
  907.         key pressed is reasonable for a "special" field. */
  908.         
  909.     /* The special formats, indicated by psf, are:
  910.     
  911.     psf             format
  912.     ---             ------
  913.     0               zip code
  914.     1               zip + 4
  915.     2               phone
  916.     3                SSN
  917.     
  918.     */
  919.  
  920.     var value = AFMergeChange(event);
  921.     var commit, noCommit;
  922.  
  923.     if(!value) return;
  924.     switch (psf)
  925.     {
  926.         case 0:
  927.             commit = AFZipCommitRegExp;
  928.             noCommit = AFZipEntryRegExp;
  929.             break;
  930.         case 1:
  931.             commit = AFZip4CommitRegExp;
  932.             noCommit = AFZip4EntryRegExp;
  933.             break;
  934.         case 2:
  935.             commit = AFPhoneCommitRegExp;
  936.             noCommit = AFPhoneEntryRegExp;
  937.             break;
  938.         case 3:
  939.             commit = AFSSNCommitRegExp;
  940.             noCommit = AFSSNEntryRegExp;
  941.             break;
  942.     }        
  943.     if(!AFExactMatch(event.willCommit ? commit : noCommit, value))
  944.     {
  945.         if (event.willCommit)
  946.             app.alert(IDS_INVALID_VALUE + " [ " + event.target.name + " ]", 0);
  947.         else
  948.             app.beep(0);
  949.         event.rc = false;
  950.     }
  951. }
  952.  
  953. function AFDate_KeystrokeEx(cFormat)
  954. {    /* This function validates the current keystroke event to make sure the
  955.     ** key pressed is reasonable for a date field. */
  956.     if(event.willCommit && !AFParseDateEx(AFMergeChange(event), cFormat)) {
  957.         /* Dates are only validated on commit */
  958.         if (event.willCommit)
  959.             app.alert(IDS_INVALID_DATE + " [ " + event.target.name + " ]", 0);
  960.         else
  961.             app.beep(0);
  962.         event.rc = false;
  963.     }
  964. }
  965.  
  966. function AFDate_Keystroke(pdf)
  967. {    /* OBSOLETE: Use AFDate_KeystrokeEx. */
  968.     var cOldFormats = new Array(
  969.         "m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy",
  970.         "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy",
  971.         "m/d/yy h:MM tt", "m/d/yy HH:MM" );
  972.  
  973.     AFDate_KeystrokeEx(cOldFormats[pdf]);
  974. }
  975.  
  976. function AFTime_Keystroke(ptf)
  977. {    /* This function validates the current keystroke event to make sure the
  978.     key pressed is reasonable for a time field. */
  979.  
  980.     if(event.willCommit && !AFParseTime(event.value, null))
  981.                     /* times are only validated on commit */
  982.     {
  983.         if (event.willCommit)
  984.             app.alert(IDS_INVALID_VALUE + " [ " + event.target.name + " ]", 0);
  985.         else
  986.             app.beep(0);
  987.         event.rc = false;
  988.     }
  989. }
  990.  
  991. function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency, bCurrencyPrepend)
  992. {       /* This function formats a numeric value according to the parameters. */
  993.  
  994.     var value = AFMakeNumber(event.value);
  995.     var sign = (value < 0 ? -1 : 1);
  996.     var f = event.target;
  997.  
  998.     if(value == null)
  999.     {
  1000.         event.value = "";
  1001.         return;
  1002.     }    
  1003.     if ((negStyle == 2 /* ParensBlack */ || negStyle == 3 /* ParensRed */) && value < 0)
  1004.         var formatStr = "(";
  1005.     else 
  1006.         var formatStr = "";
  1007.     
  1008.     if (bCurrencyPrepend)
  1009.         formatStr = formatStr + strCurrency;
  1010.         
  1011.     formatStr = formatStr + "%," + sepStyle + "." + nDec + "f";
  1012.     if (! bCurrencyPrepend)
  1013.         formatStr = formatStr + strCurrency;
  1014.         
  1015.     if ((negStyle == 2 /* ParensBlack */ || negStyle == 3 /* ParensRed */) && value < 0)
  1016.         formatStr = formatStr + ")";
  1017.  
  1018.     if (negStyle != 0 /* MinusBlack */ || bCurrencyPrepend)
  1019.         value = Math.abs(value);
  1020.         
  1021.     if (negStyle == 1 /* Red */ || negStyle == 3 /* ParensRed */) {
  1022.         if (sign > 0 )
  1023.             f.fgColor = color.black;
  1024.         else 
  1025.             f.fgColor = color.red;
  1026.     }
  1027.  
  1028.     var tmp = util.printf(formatStr, value);
  1029.     if (sign < 0 && bCurrencyPrepend && negStyle == 0)
  1030.         tmp = '-' + tmp; /* prepend the -ve sign */
  1031.     event.value = tmp;
  1032. }
  1033.  
  1034. function AFPercent_Format(nDec, sepStyle)
  1035. {       /* This function formats a percentage value according to the parameters. */
  1036.  
  1037.     var value = AFMakeNumber(event.value) * 100;
  1038.     
  1039.     var formatStr = "%," + sepStyle + "." + nDec + "f";
  1040.         
  1041.     if(value == null)
  1042.     {
  1043.         event.value = "";
  1044.         return;
  1045.     }    
  1046.  
  1047.     value = util.printf(formatStr, value);
  1048.     
  1049.     event.value = value + "%";
  1050. }
  1051.  
  1052. function AFSpecial_Format(psf)
  1053. {   /* This function formats a "special" value according to the "PropsSpecialFormat" parameter psf. */
  1054.     /* The special formats, indicated by psf, are: 0 = zip code, 1 = zip + 4, 2 = phone, 3 = SSN. */
  1055.     var value = event.value;
  1056.  
  1057.     if(!value) return;    
  1058.     switch (psf) {
  1059.     
  1060.         case 0:                         
  1061.             var formatStr = "99999";
  1062.             break;
  1063.         case 1:                         
  1064.             var formatStr = "99999-9999";
  1065.             break;
  1066.         case 2:                         /* must distinguish between 2 styles: with and without area code */
  1067.             var NumbersStr = util.printx("9999999999", value);      /* try to suck out 10 numeric chars */
  1068.             if (NumbersStr.length >= 10 )
  1069.                 var formatStr = "(999) 999-9999";
  1070.             else 
  1071.                 var formatStr = "999-9999";
  1072.             break;
  1073.         case 3:
  1074.             var formatStr = "999-99-9999";
  1075.             break;
  1076.     }
  1077.         
  1078.     event.value = util.printx(formatStr, value);
  1079. }
  1080.  
  1081. function AFParseDateYCount(cFormat)
  1082. {
  1083.     /* Determine the order of the date. */
  1084.     var yCount = 0;
  1085.     for (var i = 0; i < cFormat.length; i++) {
  1086.         switch (cFormat.charAt(i)) {
  1087.             case "\\":    /* Escape character. */
  1088.                 i++;
  1089.             break;
  1090.             case "y":
  1091.                 yCount += 1;
  1092.             break;
  1093.         }
  1094.     }
  1095.     return yCount;
  1096. }
  1097.  
  1098. function AFParseDateOrder(cFormat)
  1099. {
  1100.     /* Determine the order of the date. */
  1101.     var cOrder = "";
  1102.     for (var i = 0; i < cFormat.length; i++) {
  1103.         switch (cFormat.charAt(i)) {
  1104.             case "\\":    /* Escape character. */
  1105.                 i++;
  1106.             break;
  1107.             case "m":
  1108.                 if (cOrder.indexOf("m") == -1)
  1109.                     cOrder += "m";
  1110.             break;
  1111.             case "d":
  1112.                 if (cOrder.indexOf("d") == -1)
  1113.                     cOrder += "d";
  1114.             break;
  1115.             case "y":
  1116.                 if (cOrder.indexOf("y") == -1)
  1117.                     cOrder += "y";
  1118.             break;
  1119.         }
  1120.     }
  1121.  
  1122.     /* Make sure we have a full complement of 3 chars. */
  1123.     if (cOrder.indexOf("m") == -1)
  1124.         cOrder += "m";
  1125.     if (cOrder.indexOf("d") == -1)
  1126.         cOrder += "d";
  1127.     if (cOrder.indexOf("y") == -1)
  1128.         cOrder += "y";
  1129.  
  1130.     return cOrder;
  1131. }
  1132.  
  1133. function AFDate_FormatEx(cFormat)
  1134. {    /* cFormat is a format string with which the date is to be formatted. */
  1135.     if (!event.value) 
  1136.         return;    /* Blank fields remain blank */
  1137.  
  1138.     var date = AFParseDateEx(event.value, cFormat);
  1139.     if (!date) {
  1140.         event.value = "";
  1141.         return;
  1142.     }
  1143.     
  1144.     event.value = util.printd(cFormat, date);
  1145. }
  1146.  
  1147. function AFDate_Format(pdf)
  1148. {    /* OBSOLETE: Use AFDate_FormatEx. */
  1149.     var cOldFormats = new Array(
  1150.         "m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy",
  1151.         "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy",
  1152.         "m/d/yy h:MM tt", "m/d/yy HH:MM" );
  1153.  
  1154.     AFDate_FormatEx(cOldFormats[pdf]);
  1155. }
  1156.  
  1157. function AFTime_Format(ptf)
  1158. {    /* This function formats a time value according to the "PropsTimeFormat" parameter ptf.
  1159.     ** The time formats, indicated by ptf, are:
  1160.     ** ptf             format                                                          
  1161.     ** ---             ------                                                          
  1162.     ** 0               PTF_24HR_MM     [ 14:30      ]
  1163.     ** 1               PTF_12HR_MM     [ 2:30 PM    ]
  1164.     ** 2               PTF_24HR_MM_SS  [ 14:30:15   ]
  1165.     ** 3               PTF_12HR_MM_SS  [ 2:30:15 PM ] */
  1166.  
  1167.     if(!event.value) return;    /* Blank fields remain blank */
  1168.  
  1169.     var date = new AFParseTime(event.value, null);
  1170.     if(!date) {
  1171.         event.value = "";
  1172.         return;
  1173.     }
  1174.  
  1175.     var cFormats = new Array(
  1176.         "HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt" ); 
  1177.     
  1178.     event.value = util.printd(cFormats[ptf], date);
  1179. }
  1180.  
  1181. function AFSignatureLock(doc, cOperation, cFields, bLock)
  1182. {    // Locks or unlocks a set of fields according to the specified operation.
  1183.     /* Field name separator is one or more spaces followed by a comma, 
  1184.     ** followed by one or more spaces.
  1185.     ** or an array of field names */
  1186.      var aFields = AFMakeArrayFromList(cFields);
  1187.  
  1188.     /* Three cases: ALL, EXCEPT, THESE for the field name list. */
  1189.     if (cOperation != "THESE") {
  1190.         for (var i = 0; i < doc.numFields; i++) {
  1191.             var f = doc.getField(doc.getNthFieldName(i));
  1192.                 
  1193.             f.readonly = bLock;
  1194.          }
  1195.     }
  1196.     
  1197.     if (cOperation == "EXCEPT")
  1198.         /* EXCEPT = ALL(lock) then THESE(unlock) */
  1199.         bLock = !bLock;
  1200.  
  1201.     if (cOperation == "THESE" || (cOperation == "EXCEPT" && !bLock)) {
  1202.         for (var i = 0; i < aFields.length; i++) {
  1203.             var f = doc.getField(aFields[i]);
  1204.             var a = f.getArray();
  1205.  
  1206.             for (var j = 0; j < a.length; j++) {
  1207.                 a[j].readonly = bLock;
  1208.             }
  1209.         }
  1210.     }
  1211. }
  1212.  
  1213. function AFSignature_Format(cOperation, cFields)
  1214. {    /* This function is invoked at format time but really is used to lock fields
  1215.     ** in the document. We unlock all the specified fields if the value is
  1216.     ** null (which means the signature hasn't been applied). */
  1217.  
  1218.     var bLock = (event.value != "");
  1219.  
  1220.     AFSignatureLock(this, cOperation, cFields, bLock);
  1221. }
  1222.